package nnImplementation;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author Vincent Hellendoorn
 * @version 1.2
 * @since 18-11-2011
 */
public class ArtistSuggestionSystem2
{
	public static Artist Artists[];
	public static ArrayList<String> Tags;
	public static ArrayList<String> generalTags;
	public static ArrayList<String> subTags;
	public static ArrayList<String> addInfo;
	
	/**
	 * Initializes tags, divided in three subgroups used for classification
	 * @since 12-2011
	 */
	public static void initialiseTags()
	{
		Tags = new ArrayList<String>();
		generalTags = new ArrayList<String>();
		subTags = new ArrayList<String>();
		addInfo = new ArrayList<String>();

		generalTags.add("rock[[ ]?n[ ]?roll|[ ]?&[ ]?roll]?");
		generalTags.add("punk");
		generalTags.add("indie");
		generalTags.add("folk");
		generalTags.add("hip[-| ]?hop");
		generalTags.add("country");
		generalTags.add("rap");
		generalTags.add("jazz");
		generalTags.add("blues");
		generalTags.add("soul");
		generalTags.add("trance");
		generalTags.add("house");
		generalTags.add("techno");
		generalTags.add("funk");
		generalTags.add("pop");
		generalTags.add("fusion");
		generalTags.add("metal");
		generalTags.add("dance");
		generalTags.add("latin");
		generalTags.add("salsa");
		generalTags.add("samba");
		generalTags.add("reggae");
		generalTags.add("r(n|&)b");
		generalTags.add("dubstep");
		generalTags.add("celtic");
		generalTags.add("ballad");
		generalTags.add("swing");
		generalTags.add("(death|hard)core");
		generalTags.add("dans[e]?");
		generalTags.add("ska");
		generalTags.add("opera");
		
		subTags.add("electro[nic[a]?]?");
		subTags.add("groove");
		subTags.add("(death|black|doom) metal");
		subTags.add("alternative");
		subTags.add("underground");
		subTags.add("modern");
		subTags.add("gothic");
		subTags.add("clas[s]?ic[o]?");
		subTags.add("instrumental");
		subTags.add("heavy");
		subTags.add("singer-songwriter");
		subTags.add("acoustic");
		subTags.add("christian");
		subTags.add("gospel");
		subTags.add("hard ");
		subTags.add("hardcore");
		subTags.add("alt");
		subTags.add("emo");
		subTags.add("soundtrack");
		subTags.add("^male [vocalist]?");
		subTags.add("female [vocalist]?");
		subTags.add("singer");
		subTags.add("mainstream");
		subTags.add("fusion");
		subTags.add("disney");
		subTags.add("rasta");
		subTags.add("piano");
		subTags.add("romantic");
		subTags.add("actor");
		subTags.add("ambient");
		subTags.add("new age");
		subTags.add("neo");
		subTags.add("urban");
		subTags.add("bass");
		subTags.add("symphonic");
		subTags.add("black");
		subTags.add("eurodance");
		subTags.add("melodic");
		subTags.add("psychedelic");
		subTags.add("garage");
		subTags.add("industrial");
		subTags.add("chanson");
		subTags.add("boyband");
		subTags.add("parody");
		subTags.add("dub");
		subTags.add("humor");
		subTags.add("old[ ]?s[ch|k]ool");
		subTags.add("surf");
		subTags.add("praise");
		subTags.add("scream");
		subTags.add("girl group");
		subTags.add("south[ern]?");
		subTags.add("progressive");
		subTags.add("experimental");
		subTags.add("meditative");
		subTags.add("oldies");
		subTags.add("old( |-)");
		subTags.add("nouvelle");
		subTags.add("speed");
		subTags.add("lounge");
		subTags.add("post");
		subTags.add("traditional");
		subTags.add("band");
		subTags.add("new wave");
		subTags.add("children");
		subTags.add("musical");
		subTags.add("remix");
		subTags.add("political");
		subTags.add("dark");
		subTags.add("downtempo");
		subTags.add("tech(-| )");
		subTags.add("art(istic| )");
		
		addInfo.add("10s");
		addInfo.add("00s");
		addInfo.add("90s");
		addInfo.add("80s");
		addInfo.add("70s");
		addInfo.add("60s");
		addInfo.add("50s");
		addInfo.add("america[n]?");
		addInfo.add("russia[n]?");
		addInfo.add("belgi(an|um)");
		addInfo.add("canad(ian|a)");
		addInfo.add("fr(ench|anc[e]?)");
		addInfo.add("ital(ian|y)");
		addInfo.add("iceland[ic]?");
		addInfo.add("brit(ish|.+)");
		addInfo.add("german|deutsch");
		addInfo.add("dutch|nederland[s]?");
		addInfo.add("norw[egian|way]?");
		addInfo.add("fin(land|nish)");
		addInfo.add("australia[n]?");
		addInfo.add("slovak");
		addInfo.add("japan[ese]?");
		addInfo.add("afri(k|c)a");
		addInfo.add("colombia[n]?");
		addInfo.add("latvia[n]?");
		addInfo.add("danish|d(e|a)nmark");
		addInfo.add("iraq[i]?");
		addInfo.add("portug(al|uese)");
		addInfo.add("pol(and|ish)");
		addInfo.add("hungaria[n]?");
		addInfo.add("colombia[n]?");
		addInfo.add("spa(in|nish)|espan(a|ol)");
		addInfo.add("jamaica[n]?");
		addInfo.add("turk(ey|ish)");
		addInfo.add("israel[i]?");
		addInfo.add("korea[n]?");
		addInfo.add("mexic(o|an)");
		addInfo.add("puerto[ ]?ric(an|o)");
		addInfo.add("brazil[ian|brasileira]?");
		addInfo.add("macedonia[n]?");
		addInfo.add("swed(en|ish)");
		addInfo.add("argentin[ian|e]?");
		addInfo.add("filipino|philippine[s]");
		addInfo.add("west[-| ]?coast");
		addInfo.add("east[-| ]?coast");
		addInfo.add("california");
		addInfo.add("minnesota");
		addInfo.add("galicia");
		addInfo.add("scot(tish|land)");
		
		Tags.addAll(generalTags);
		Tags.addAll(subTags);
		Tags.addAll(addInfo);
	}
	
	/**
	 * Connects to the database and loads in all artists, using the known tables
	 * Was adapted to fit new tables
	 * @since 11-2011
	 * @param dbName Name of the database
	 * @version 1.1
	 */
	public static void loadArtists(String dbName)
	{
		ArrayList<Artist> as = new ArrayList<Artist>();
		Connection con = null;
		try
		{
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			con = DriverManager.getConnection("jdbc:mysql://sql.ewi.tudelft.nl/", "ikemusic2", "1234567890");
		}
		catch (SQLException e1)
		{
			e1.printStackTrace();
		}
		catch (InstantiationException e)
		{
			e.printStackTrace();
		}
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
		Statement stmt = null;
		String query = "select * from " + dbName + ".NewArtist";
		try
		{
			stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery(query);
			int count = 0;
			while (rs.next())
			{
				/*
				 * Procedure: Upon reading a new artist, we have to know if there isn't already an artist object
				 * of this artist; if not: create it and fill it. If one of this artists' similar artists is not yet known, he will 
				 * have to be added as a new artist. Eventually all empty objects (similars which are never used) are removed.
				 * This procedure requires a lot of time for checking and is therefore rather slow.
				 * It didn't form a significant barrier however, requiring 10-20 minutes to read in 90000 artists.
				 */
				count++;
				if (count % 1000 == 0)
					System.out.println("Read " + count + " artists");
				Artist newArtist = null;
				String name = rs.getString("name");
				for (int i = 0; i < as.size(); i++)
				{
					if (as.get(i).getName().equals(name))
						newArtist = as.get(i);
				}

				String[] tags = new String[5];
				for (int i = 0; i < 5; i++)
				{
					tags[i] = rs.getString("genre" + (i + 1));
				}

				Artist[] similar = new Artist[5];
				for (int i = 0; i < 5; i++)
				{
					String artist = rs.getString("similar" + (i + 1));
					for (int j = 0; j < as.size(); j++)
					{
						if (as.get(j).getName().equals(artist))
							similar[i] = as.get(j);
					}
					if (similar[i] == null)
					{
						as.add(new Artist(artist));
						similar[i] = as.get(as.size() - 1);
					}
				}
				int listenCount = rs.getInt("listened");
				int[] yearsActive = { rs.getInt("year1"), rs.getInt("year2") };
				int id = rs.getInt("id");
				boolean added = false;
				for (int i = 0; i < as.size(); i++)
				{
					if (as.get(i).getName().equals(name))
					{
						as.get(i).setTags(tags);
						as.get(i).setSimilarArtists(similar);
						as.get(i).setListenCount(listenCount);
						as.get(i).setYearsActive(yearsActive);
						as.get(i).setID(id);
						added = true;
					}
				}
				if (!added)
				{
					newArtist = new Artist(name, similar, tags, yearsActive, listenCount, id);
					as.add(newArtist);
				}
			}
			for (int i = 0; i < as.size(); i++)
			{
				if (as.get(i).isShallow())
				{
					as.remove(i);
					i--;
				}
			}
			/*
			 * On reading in, the tags of every artist are also classified and reduced to (0,3) tags.
			 * This is done in two steps:
			 * First every one of the three categories gets 'a chance' to add one tag, by checking whether any tag
			 * matches the regular pattern of one tag within this category.
			 * Secondly, if a category doesn't yet have a tag, an attempt will be made to distinguish another
			 * tag for one of the other categories from the list of tags of this artist.
			 * In this way every artist will have as many tags possible in as many different categories possible
			 */
			for (int i = 0; i < as.size(); i++)
			{
				String[] tags = new String[3];
				boolean[] tag = new boolean[3];
				Arrays.fill(tag, false);

				// Tag 0
				for (int j = 0; j < as.get(i).getTags().length; j++)
				{
					if(tag[0])
						break;
					for (int k = 0; k < generalTags.size(); k++)
					{
						if (as.get(i).getTag(j) != "" && as.get(i).getTag(j).matches(".*" + generalTags.get(k) + ".*"))
						{
							tags[0] = generalTags.get(k);
							tag[0] = true;
							break;
						}
					}
				}
				// Tag 1, try to find one from sub-tags
				for (int j = 0; j < as.get(i).getTags().length; j++)
				{
					if (tag[1])
						break;
					for (int k = 0; k < subTags.size(); k++)
					{
						if (as.get(i).getTag(j) != "" && as.get(i).getTag(j).matches(".*" + subTags.get(k) + ".*"))
						{
							tags[1] = subTags.get(k);
							tag[1] = true;
							break;
						}
					}
				}
				// Tag 2, try to get one from additional info tags
				for (int j = 0; j < as.get(i).getTags().length; j++)
				{
					if (tag[2])
						break;
					for (int k = 0; k < addInfo.size(); k++)
					{
						if (as.get(i).getTag(j) != "" && as.get(i).getTag(j).matches(".*" + addInfo.get(k) + ".*"))
						{
							tags[2] = addInfo.get(k);
							tag[2] = true;
							break;
						}
					}
				}
				// Still no Tag 0
				if (!tag[0])
				{
					for (int j = 0; j < as.get(i).getTags().length; j++)
					{
						if (tag[0])
							break;
						for (int k = 0; k < subTags.size(); k++)
						{
							if (as.get(i).getTag(j) != "" && !(subTags.get(k).equals(tags[1])) && !(subTags.get(k).equals(tags[2]))
									&& as.get(i).getTag(j).matches(".*" + subTags.get(k) + ".*"))
							{
								tags[0] = subTags.get(k);
								tag[0] = true;
								break;
							}
						}
					}
				}
				if (!tag[0])
				{
					for (int j = 0; j < as.get(i).getTags().length; j++)
					{
						if (tag[0])
							break;
						for (int k = 0; k < addInfo.size(); k++)
						{
							if (as.get(i).getTag(j) != "" && !(addInfo.get(k).equals(tags[1])) && !(addInfo.get(k).equals(tags[2]))
									&& as.get(i).getTag(j).matches(".*" + addInfo.get(k) + ".*"))
							{
								tags[0] = addInfo.get(k);
								tag[0] = true;
								break;
							}
						}
					}
				}
				// Still no tag 1
				if (!tag[1])
				{
					for (int j = 0; j < as.get(i).getTags().length; j++)
					{
						if (tag[1])
							break;
						for (int k = 0; k < generalTags.size(); k++)
						{
							if (as.get(i).getTag(j) != "" && !(generalTags.get(k).equals(tags[0])) && !(generalTags.get(k).equals(tags[2]))
									&& as.get(i).getTag(j).matches(".*" + generalTags.get(k) + ".*"))
							{
								tags[1] = generalTags.get(k);
								tag[1] = true;
								break;
							}
						}
					}
				}
				if (!tag[1])
				{
					for (int j = 0; j < as.get(i).getTags().length; j++)
					{
						if (tag[1])
							break;
						for (int k = 0; k < addInfo.size(); k++)
						{
							if (as.get(i).getTag(j) != "" && !(addInfo.get(k).equals(tags[0])) && !(addInfo.get(k).equals(tags[2]))
									&& as.get(i).getTag(j).matches(".*" + addInfo.get(k) + ".*"))
							{
								tags[1] = addInfo.get(k);
								tag[1] = true;
								break;
							}
						}
					}
				}

				// Still no tag 2
				if (!tag[2])
				{
					for (int j = 0; j < as.get(i).getTags().length; j++)
					{
						if (tag[2])
							break;
						for (int k = 0; k < generalTags.size(); k++)
						{
							if (as.get(i).getTag(j) != "" && !(generalTags.get(k).equals(tags[0])) && !(generalTags.get(k).equals(tags[1]))
									&& as.get(i).getTag(j).matches(".*" + generalTags.get(k) + ".*"))
							{
								tags[2] = generalTags.get(k);
								tag[2] = true;
								break;
							}
						}
					}
				}
				if (!tag[2])
				{
					for (int j = 0; j < as.get(i).getTags().length; j++)
					{
						if (tag[2])
							break;
						for (int k = 0; k < subTags.size(); k++)
						{
							if (as.get(i).getTag(j) != "" && !(subTags.get(k).equals(tags[0])) && !(subTags.get(k).equals(tags[1]))
									&& as.get(i).getTag(j).matches(".*" + subTags.get(k) + ".*"))
							{
								tags[2] = subTags.get(k);
								tag[2] = true;
								break;
							}
						}
					}
				}
				// This final procedure is only for ease of use; tags resolve in this way will never be used
				for (int j = 0; j < 3; j++)
				{
					if (as.get(i).getTag(j) != "" && !tag[j])
					{
						tags[j] = as.get(i).getTag(j);
					}
				}
				as.get(i).setTags(tags);
			}
			Artists = as.toArray(new Artist[1]);
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
		finally
		{
			if (stmt != null)
			{
				try
				{
					stmt.close();
				}
				catch (SQLException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * Write tags as decided in 'intialiseTags' to database. 
	 * Upon change, also change table 'NewArtistGenre', 'NewUserGenre', 'NewSuggestions'
	 * @version 1.0
	 * @since 12-2011
	 */
	public static void writeTags()
	{
		Connection con = null;
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			con = DriverManager.getConnection("jdbc:mysql://sql.ewi.tudelft.nl/", "ikemusic2", "1234567890");
		} catch (SQLException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		String dbName = "ikemusic2";
		PreparedStatement pstmt = null;
		try {
			for(int i = 0; i < Tags.size(); i++)
			{
				String update = "INSERT INTO " + dbName + ".NewGenre VALUES(id, ?, ?)";
				pstmt = con.prepareStatement(update, Statement.RETURN_GENERATED_KEYS);
				pstmt.setString(1, Tags.get(i));
				pstmt.setString(2, Tags.get(i));
				pstmt.executeUpdate();
			}
	    } catch (SQLException e ) {
	    	e.printStackTrace();
	    } finally {
	    	if (pstmt != null) {
	    		try {
	    			pstmt.close();
	    		} catch (SQLException e) {
	    			e.printStackTrace();
	    		} 	
	    	}
	    }
	}

	/**
	 * Creates the table which forms the bridge between an artist and his tags. These are the
	 * classified and normalized tags and are used in every calculation
	 * @param dbName Name of the database
	 */
	public static void createArtistTagsTable(String dbName)
	{
		Connection con = null;
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			con = DriverManager.getConnection("jdbc:mysql://sql.ewi.tudelft.nl/", "ikemusic2", "1234567890");
		} catch (SQLException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Statement stmt = null;
		String query = "select * from " + dbName + ".NewArtist";
	    try {
	    	stmt = con.createStatement();
	    	ResultSet rs = stmt.executeQuery(query);
	    	int count = 0;
	    	while (rs.next()) {
	    		count++;
	    		if(count%1000 == 0)
	    			System.out.println("Read " + count + " artists");
	    		int id = rs.getInt("id");
	    		String[] tagsOld = new String[5];
	    		for(int i = 0; i < 5; i++)
	    		{
	    			tagsOld[i] = rs.getString("genre" + (i+1));
	    		}
	    		PreparedStatement pstmt;
	    		stmt = con.createStatement();
	    		
	    		// INSERT TAGS STARTS HERE
	    		String[] tags = new String[3];
	    		boolean[] tag = new boolean[3];
	    		Arrays.fill(tag, false);
	    		
	    		/*
				 * On reading in, the tags of every artist are also classified and reduced to (0,3) tags.
				 * This is done in two steps:
				 * First every one of the three categories gets 'a chance' to add one tag, by checking whether any tag
				 * matches the regular pattern of one tag within this category.
				 * Secondly, if a category doesn't yet have a tag, an attempt will be made to distinguish another
				 * tag for one of the other categories from the list of tags of this artist.
				 * In this way every artist will have as many tags possible in as many different categories possible
				 */
				// Tag 0
				for (int j = 0; j < tagsOld.length; j++)
				{
					if (tag[0])
						break;
					for (int k = 0; k < generalTags.size(); k++)
					{
						if (tagsOld[j].matches(".*"+generalTags.get(k)+".*"))
						{
							tags[0] = generalTags.get(k);
							tag[0] = true;
							break;
						}
					}
				}
				// Tag 1, try to find one from sub-tags
				for (int j = 0; j < tagsOld.length; j++)
				{
					if (tag[1])
						break;
					for (int k = 0; k < subTags.size(); k++)
					{
						if (tagsOld[j].matches(".*"+subTags.get(k)+".*"))
						{
							tags[1] = subTags.get(k);
							tag[1] = true;
							break;
						}
					}
				}
				// Tag 2, try to get one from additional info tags
				for (int j = 0; j < tagsOld.length; j++)
				{
					if (tag[2])
						break;
					for (int k = 0; k < addInfo.size(); k++)
					{
						if (tagsOld[j].matches(".*"+addInfo.get(k)+".*"))
						{
							tags[2] = addInfo.get(k);
							tag[2] = true;
							break;
						}
					}
				}
				// Still no Tag 0
				if (!tag[0])
				{
					for (int j = 0; j < tagsOld.length; j++)
					{
						if (tag[0])
							break;
						for (int k = 0; k < subTags.size(); k++)
						{
							if (!(subTags.get(k).equals(tags[1])) && !(subTags.get(k).equals(tags[2]))
									&& tagsOld[j].matches(".*"+subTags.get(k)+".*"))
							{
								tags[0] = subTags.get(k);
								tag[0] = true;
								break;
							}
						}
					}
				}
				if (!tag[0])
				{
					for (int j = 0; j < tagsOld.length; j++)
					{
						if (tag[0])
							break;
						for (int k = 0; k < addInfo.size(); k++)
						{
							if (!(addInfo.get(k).equals(tags[1])) && !(addInfo.get(k).equals(tags[2]))
									&& tagsOld[j].matches(".*"+addInfo.get(k)+".*"))
							{
								tags[0] = addInfo.get(k);
								tag[0] = true;
								break;
							}
						}
					}
				}
				// Still no tag 1
				if (!tag[1])
				{
					for (int j = 0; j < tagsOld.length; j++)
					{
						if (tag[1])
							break;
						for (int k = 0; k < generalTags.size(); k++)
						{
							if (!(generalTags.get(k).equals(tags[0])) && !(generalTags.get(k).equals(tags[2]))
									&& tagsOld[j].matches(".*"+generalTags.get(k)+".*"))
							{
								tags[1] = generalTags.get(k);
								tag[1] = true;
								break;
							}
						}
					}
				}
				if (!tag[1])
				{
					for (int j = 0; j < tagsOld.length; j++)
					{
						if (tag[1])
							break;
						for (int k = 0; k < addInfo.size(); k++)
						{
							if (!(addInfo.get(k).equals(tags[0])) && !(addInfo.get(k).equals(tags[2]))
									&& tagsOld[j].matches(".*"+addInfo.get(k)+".*"))
							{
								tags[1] = addInfo.get(k);
								tag[1] = true;
								break;
							}
						}
					}
				}

				// Still no tag 2
				if (!tag[2])
				{
					for (int j = 0; j < tagsOld.length; j++)
					{
						if (tag[2])
							break;
						for (int k = 0; k < generalTags.size(); k++)
						{
							if (!(generalTags.get(k).equals(tags[0])) && !(generalTags.get(k).equals(tags[1]))
									&& tagsOld[j].matches(".*"+generalTags.get(k)+".*"))
							{
								tags[2] = generalTags.get(k);
								tag[2] = true;
								break;
							}
						}
					}
				}
				if (!tag[2])
				{
					for (int j = 0; j < tagsOld.length; j++)
					{
						if (tag[2])
							break;
						for (int k = 0; k < subTags.size(); k++)
						{
							if (!(subTags.get(k).equals(tags[0])) && !(subTags.get(k).equals(tags[1]))
									&& tagsOld[j].matches(".*"+subTags.get(k)+".*"))
							{
								tags[2] = subTags.get(k);
								tag[2] = true;
								break;
							}
						}
					}
				}
				for (int j = 0; j < 3; j++)
				{
					if(!tag[j])
					{
						tags[j] = "";
					}
				}
		    	String update = "INSERT INTO "+dbName+".NewArtistGenre VALUES(?, ?, ?, ?)";
		    	pstmt = con.prepareStatement(update, Statement.RETURN_GENERATED_KEYS);

		    	ResultSet rs2;
		    	pstmt.setInt(1, id);
		    	int idGenre;
		    	for(int j = 0; j < 3; j++)
		    	{
		    		rs2 = stmt.executeQuery("SELECT id FROM " + dbName + ".NewGenre WHERE name = '" + tags[j]+ "'");
			    	if(rs2.next())
			    	{
				    	idGenre = rs2.getInt("id");
				    	pstmt.setInt(j+2, idGenre);
			    	}
			    	else
			    	{
			    		pstmt.setInt(j+2, 0);
			    	}
		    	}
		    	pstmt.executeUpdate();
		    	if(count%100 == 0)
		    		System.out.println("Wrote " + count + " rows");
		    }
	    } catch(Exception e2) {
    		e2.printStackTrace();
    	}
	}
	
	/**
	 * Creates the table that calculates suggestions for each artist
	 * Writes to a file because this is significantly faster and more robust than writing
	 * directly to the database. It can be adapted to spread results over more files.
	 * Performance improvements could be made by using separate threads.
	 * @param dbName Name of the database
	 * @param filename Name of the file to write to
	 * @param amount Number of suggestions per artist
	 * @version 1.3
	 */
	public static void createSuggestionsTable(String dbName, String filename, int amount)
	{
		File f = new File(filename);
		FileWriter fw = null;
		try
		{
			fw = new FileWriter(f);
		}
		catch (IOException e1)
		{
			e1.printStackTrace();
		}
		for (int i = 0; i < Artists.length; i++)
		{
			if(i%100 == 0)
				System.out.println(i);
			int id = Artists[i].getID();
			ArrayList<Result> result = new ArrayList<Result>();
			double[] compare = new double[Artists.length];

			for (int j = 0; j < Artists.length; j++)
			{
				if(Artists[j].getID() == id)
					result.add(new Result(275, id));
				if (contains(Artists[i].getSimilarArtists(), Artists[j]))
					compare[j] += .5;
				if (compare[j] == 0 && contains(Artists[j].getSimilarArtists(), Artists[i]))
					compare[j] += .35;
				for(int k = 0; k < Artists[j].getSimilarArtists().length; k++)
				{
					if (contains(Artists[i].getSimilarArtists(), Artists[j].getSimilarArtist(k)))
						compare[j] += 0.2;
				}
				for(int k = 0; k < Artists[i].getTags().length; k++)
				{
					if (contains(Artists[j].getTags(), Artists[i].getTag(k)))
						compare[j] += 0.4;
				}

				double log1 = Math.log10(Artists[i].getListenCount());
				double log2 = Math.log10(Artists[j].getListenCount());
				compare[j] += Math.exp(-Math.pow((log1 - log2), 2) / 3.25) - .5;
				
				int averageYear1 = (Artists[i].getYearsActive()[0] + Artists[i].getYearsActive()[1]) / 2;
				int averageYear2 = (Artists[j].getYearsActive()[0] + Artists[j].getYearsActive()[1]) / 2;
				compare[j] += Math.exp(-Math.pow(averageYear1 - averageYear2, 2) / 144) - .5;
				result.add(new Result((int) Math.round(100 * compare[j]) - 125, Artists[j].getID()));
			}
			for(int j = 0; j < amount; j++)
			{
				int max = 0;
				Result best = result.get(0);
				for(int k = 1; k < result.size(); k++)
				{
					if(result.get(k).score > max)
					{
						best = result.get(k);
						max = best.score;
					}
				}
				try
				{
					fw.append("INSERT INTO ikemusic2.NewSuggestions VALUES(" + id + ", " + best.index + ", " + best.score + ", " + (best.score-50) + ");\n");
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				result.remove(best);
			}
		}
		System.out.println("Suggestions written");
	}
	
	/**
	 * Method create to shorten code, testing whether an object is in a given array
	 * @param array The array
	 * @param object The object
	 * @return "array contains object?"
	 */
	public static boolean contains(Object[] array, Object object)
	{
		for(int i = 0; i < array.length; i++)
		{
			try{
				if(array[i].equals(object))
					return true;
			}
			catch(NullPointerException e){
				return false;
			}
		}
		return false;
	}
	
	public static void main(String[] args)
	{
		String dbName = "ikemusic2";
		initialiseTags();
		loadArtists(dbName);
		//writeTags();
		//createArtistTagsTable(dbName);
		//createSuggestionsTable(dbName, "data6.txt", 20);
	}
}
